package com.duobaoyu.dby.supply.biz.strategy.message.refund;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.math.Money;
import com.duobaoyu.dby.common.core.constant.CommonConstants;
import com.duobaoyu.dby.common.mybatis.util.EnumUtils;
import com.duobaoyu.dby.supply.biz.client.boundary.refund.AfterSaleBoundaryClient;
import com.duobaoyu.dby.supply.biz.enums.AfterSaleSourceEnum;
import com.duobaoyu.dby.supply.biz.exception.SupplyChainBizException;
import com.duobaoyu.dby.supply.common.biz.bo.refund.AfterSaleItemOutBO;
import com.duobaoyu.dby.supply.common.biz.bo.refund.AfterSaleOutBO;
import com.duobaoyu.dby.supply.common.biz.bo.refund.AfterSaleStateContext;
import com.duobaoyu.dby.supply.core.framework.strategy.AbstractStrategy;
import com.google.common.collect.Lists;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.ObjectUtils;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * Created by shuming on 2023/10/13 09:22
 * 售后状态变更渠道处理
 */
public abstract class AbstractChannelAfterSaleStateChangeHandler extends AbstractStrategy<AfterSaleStateChangeMessageAsyncHandler.Context, Void> {

    @Resource
    protected AfterSaleBoundaryClient afterSaleBoundaryClient;


    /**
     * 渠道编码
     *
     * @return
     */
    protected Set<String> channelCodes() {
        return Collections.emptySet();
    }

    @Override
    public boolean support(Object... args) {
        if (ObjectUtils.isNotEmpty(args) && CollectionUtils.isNotEmpty(this.channelCodes()) &&
                args.length == CommonConstants.ONE) {
            return Arrays.stream(args)
                    .filter(item -> item instanceof String)
                    .anyMatch(item -> this.channelCodes().contains((String) item));
        }
        return false;
    }


    protected List<AfterSaleStateContext.AfterSaleUpdateItemInfo> buildRefundInfo(BigDecimal channelRefundAmount,
                                                                                  BigDecimal channelFreightRefundInfo,
                                                                                  AfterSaleOutBO afterSale) {
        if (Objects.isNull(channelRefundAmount)) {
            return null;
        }
        Money channelRealRefundAmount = new Money(channelRefundAmount);
        // 订单取消
        if (EnumUtils.eq(AfterSaleSourceEnum.SYSTEM,afterSale.getAfterSaleSource())) {
            Money itemTotalAmount = afterSale.getItems().stream().map(e -> new Money(e.getChannelActualPaidAmount()))
                    .reduce(new Money(), Money::add);
            Money difference = channelRealRefundAmount.subtract(itemTotalAmount);
            if (difference.compareTo(new Money()) < 0) {
                SupplyChainBizException.fail("渠道退款金额小于商品实付金额");
            }
            final Money[] channelRealFreightRefundAmount = {Optional.ofNullable(channelFreightRefundInfo)
                    .map(Money::new).orElse(difference)};
            return afterSale.getItems().stream().map(item -> {
                AfterSaleStateContext.AfterSaleUpdateItemInfo afterSaleUpdateItem = new AfterSaleStateContext.AfterSaleUpdateItemInfo();
                afterSaleUpdateItem.setSkuCode(item.getSkuCode());
                afterSaleUpdateItem.setChannelActualRefundAmount(item.getChannelActualPaidAmount());
                afterSaleUpdateItem.setChannelFreightActualRefundAmount(channelRealFreightRefundAmount[0].getAmount());
                // 运费添加其中一个商品
                channelRealFreightRefundAmount[0] = channelRealFreightRefundAmount[0]
                        .subtract(new Money(afterSaleUpdateItem.getChannelFreightActualRefundAmount()));
                return afterSaleUpdateItem;
            }).collect(Collectors.toList());
        } else {
            AfterSaleItemOutBO first = CollUtil.getFirst(afterSale.getItems());
            boolean existFreightRefund = channelRealRefundAmount.compareTo(new Money(afterSale.getApplyRefundAmount()))
                    > CommonConstants.ZERO;
            AfterSaleStateContext.AfterSaleUpdateItemInfo afterSaleUpdateItem = new AfterSaleStateContext.AfterSaleUpdateItemInfo();
            afterSaleUpdateItem.setSkuCode(first.getSkuCode());
            afterSaleUpdateItem.setChannelActualRefundAmount(existFreightRefund ? afterSale.getApplyRefundAmount() :
                    channelRealRefundAmount.getAmount());
            afterSaleUpdateItem.setChannelFreightActualRefundAmount(existFreightRefund ?
                    channelRealRefundAmount.subtract(new Money(afterSaleUpdateItem.getChannelActualRefundAmount())).getAmount()
                    : BigDecimal.ZERO);
            return Lists.newArrayList(afterSaleUpdateItem);
        }
    }
}
